﻿<!DOCTYPE html>
<head>

	<link rel="stylesheet" type="text/css" href="style.css" />
	<link rel="stylesheet" type="text/css" href="popup.css" />

	<title>¤TPTM™: ducdat0507's The Prestige Tree Modfinder™</title>

	<link href="https://fonts.googleapis.com/css?family=Inconsolata" rel="stylesheet">
	<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
	<script>
		let app = {} 

        function fetchParent() {
            fetch("https://api.github.com/repos/Acamaeda/The-Modding-Tree")
                .then(res => {
                    if (res.status == 200) {
                        res.json()
                            .then(json => {
                                app.statusText = `
                                    The Modding Tree currently has ${json["forks"]} forks.
                                `
                                for (var a = 1; a <= Math.min(Math.ceil(json["forks"] / 100), 5); a++) fetchChildren(a)
                            })
                    } else if (res.status == 403) {
                        app.statusText = "Due to several reasons, GitHub only allows a limited amount of API calls per computer every once in a while."
                        fetch("https://api.github.com/rate_limit")
                            .then(res => {
                                res.json().then(json => { if (json.resources && json.resources.core && json.resources.core.reset) app.statusText += "<br/>Please try again in " + formatTime(json.resources.core.reset * 1000 - new Date()) + "."; console.log(json.resources.core.reset) }) })
                        console.log(res)
                    } else {
                        app.statusText = "Something gone wrong???"
                        console.log(res)
                    }
                })
                .catch(error => {
                    app.statusText = "Something gone wrong???"
                    console.log(error)
                });
        }

        function fetchChildren(page = 1) {
            fetch("https://api.github.com/repos/Acamaeda/The-Modding-Tree/forks?page=" + page + "&per_page=100&sort=newest")
                .then(res => {
                    if (res.status == 200) {
                        res.json()
                            .then(json => {
                                app.mods = app.mods.concat(json)
                                app.statusText = `
                                    <button class="tabButton" style="border-color:white;padding:5px;margin:10px 0;font-size:16px" onclick="setTab('sort')"><span>Sort...</button>
                                    <button class="tabButton" style="border-color:white;padding:5px;margin:10px 0;font-size:16px" onclick="setTab('filter')"><span>Filter...</button>
                                `
                                if (app.mods.sort) app.mods.sort(sortMods);
                            })
                    } else if (res.status == 403 && res.statusText == "rate limit exceeded") {
                        app.statusText = "Due to several reasons, GitHub only allows a limited amount of API calls per computer every once in a while."
                        fetch("https://api.github.com/rate_limit")
                            .then(res => {
                                res.json().then(json => { if (json.resources && json.resources.core && json.resources.core.reset) app.statusText += "<br/>Please try again in " + formatTime(json.resources.core.reset * 1000 - new Date()) + "."; console.log(json.resources.core.reset) }) })
                        console.log(res)
                    } else {
                        app.statusText = "Something gone wrong???"
                        console.log(res)
                    }
                })
                .catch(error => {
                    app.statusText = "Something gone wrong???"
                    console.log(error)
                });
        }

        function update() {
            app.mods = []
            app.statusText = "Patience is a virtue, I guess"
            fetchParent()
		}

        function formatTime(ms) {
            if (ms < 0) return "in the future???"
            if (ms == 0) return "literally right now"
			if (ms < 1000) return ms.toLocaleString("en-US") + "ms"
            ms /= 1000
            if (ms < 60) return Math.floor(ms).toLocaleString("en-US") + "s"
            ms /= 60
            if (ms < 60) return Math.floor(ms).toLocaleString("en-US") + "m " + Math.floor((ms % 1) * 60).toLocaleString("en-US") + "s"
            ms /= 60
            if (ms < 24) return Math.floor(ms).toLocaleString("en-US") + "h " + Math.floor((ms % 1) * 60).toLocaleString("en-US") + "m"
            ms /= 24
            if (ms < 365) return Math.floor(ms).toLocaleString("en-US") + "d " + Math.floor((ms % 1) * 24).toLocaleString("en-US") + "h"
            ms /= 365
            return Math.floor(ms).toLocaleString("en-US") + "y " + Math.floor((ms % 1) * 365).toLocaleString("en-US") + "d"
        }

        function setTab(tab) {
            app.tab = app.tab == tab ? "" : tab;
            app.mods.sort(sortMods)
        }

        function setSortOrder(order) {
            app.sortOrder = order
            app.mods.sort(sortMods)
        }

        function setSortRule(rule) {
            app.sortRule = rule
            app.mods.sort(sortMods)
        }

        function sortMods(x, y) {
            if (x[app.sortRule] < y[app.sortRule]) {
                return 1 * app.sortOrder;
            }
            if (x[app.sortRule] > y[app.sortRule]) {
                return -1 * app.sortOrder;
            }
            return 0;
        }

        function filter(mods) {
            return mods.filter(repo => 
                new Date(repo.updated_at) - new Date(repo.created_at) > app.timeCreationFilter * 1000
                && new Date() - new Date(repo.updated_at) < app.timeUpdatedFilter * 1000
            );
        }

		function load() {
            app = new Vue({
                el: "#finderApp",
                data: {
                    mods: [],
                    sortRule: "updated_at",
                    sortOrder: 1,
                    width: 100,
                    statusText: "",
                    tab: "",
                    timeCreationFilter: 0,
                    timeUpdatedFilter: +"Infinity",
                },
            })
			update()
        }

        // By default, all descrpitions matching these will not be shown. 
        // This is to prevent the TMT's default descriptions from appearing as that mod's desciption.
        let descFilter = [
            "Create your own tree (or non-tree) of prestige upgrades!",
            "Create your own tree of prestige upgrades!",
            "",
        ]

        setInterval(() => app.width = window.innerWidth, 100)
		
	</script>
    <style>
        select, .tabItem {
            background-color: #ffffff;
            color: #3f3f3e;
            padding: 3px;
            border: 2px solid #0000002f;
            border-radius: 5px;
            font-size: 16px;
        }

        .navButton {
            border: 1px solid #e3e3e2;
            background: linear-gradient(#ffffff, #f6f6f5);
            color: #3f3f3e;
            width: calc(33% - 7px);
            padding: 3px;
            height: 12px;
            font-size: 12px;
            display: inline-block;
        }
        .navButton.disabled {
            color: #c9c9c9;
            pointer-events: none;
        }
    </style>
</head>
<body onload="load()" style="overflow-y:scroll">
    <div id="finderApp" style="padding:5px">
        <div>
            <br />
            <h3>ducdat0507's The Prestige Tree Modfinder™</h3><br />
            This basically fetches all forks from TMT's repository using the GitHub API.<br />
            <br />
        </div>
        <div v-html="statusText + '<br/>'"></div>
        <div v-bind:style="{'display': tab == 'sort' ? '' : 'none'}">
            Sort:<div style="font-size:5px">&nbsp;</div>By: 
            <select onchange="setSortRule(this.value)" v-bind:value="sortRule">
                <option value="updated_at">Update date</option>
                <option value="created_at">Creation date</option>
                <option value="stargazers_count">Stars</option>
                <option value="open_issues_count">Open issues</option>
            </select>
            &nbsp;Order: 
            <button class="tabItem" style="width:29px; border-radius: 5px 0 0 5px" v-bind:style="{'opacity': sortOrder == -1 ? 1 : .5}" onclick="setSortOrder(-1)"><span>▼</button><!--
            --><button class="tabItem" style="width:29px; border-radius: 0 5px 5px 0" v-bind:style="{'opacity': sortOrder == 1 ? 1 : .5}" onclick="setSortOrder(1)"><span>▲</button>
            <br/>&nbsp;
        </div>
        <div v-bind:style="{'display': tab == 'filter' ? '' : 'none'}">
            Updated since:<div style="font-size:5px">&nbsp;</div>Creation: 
            <select onchange="app.timeCreationFilter = +this.value" v-bind:value="timeCreationFilter">
                <option value="0">Unfiltered</option>
                <option value="60">&gt; 1 minute</option>
                <option value="600">&gt; 10 minutes</option>
                <option value="3600">&gt; 1 hour</option>
                <option value="14400">&gt; 4 hours</option>
                <option value="43200">&gt; 12 hours</option>
                <option value="86400">&gt; 1 day</option>
                <option value="259200">&gt; 3 days</option>
                <option value="604800">&gt; 7 days</option>
                <option value="2592000">&gt; 1 month</option>
            </select>
            &nbsp;Now: 
            <select onchange="app.timeUpdatedFilter = +this.value" v-bind:value="timeUpdatedFilter">
                <option value="Infinity">Unfiltered</option>
                <option value="31104000">&lt; 1 year</option>
                <option value="20736000">&lt; 8 months</option>
                <option value="10368000">&lt; 4 months</option>
                <option value="5184000">&lt; 2 months</option>
                <option value="2592000">&lt; 1 month</option>
                <option value="604800">&lt; 7 days</option>
                <option value="86400">&lt; 1 day</option>
            </select>
            <br/>&nbsp;
        </div>
        <div v-for="repo in filter(mods)" v-bind:style="{'width': 'calc(' + (100 / Math.max(Math.floor((width - 10) / 400), 1)) + '% - 10px)'}" style="display:inline-flex;margin:0;padding:5px;transition:none">
            <div v-if="repo.owner" style="text-align:left;border:4px solid #272725;background:linear-gradient(#383838, #2a2a29);border-radius:4px;padding:5px;width:100%">
                <table>
                    <tr>
                        <td><img v-bind:src="repo.owner.avatar_url" style="width:50px;height:50px;border-radius:8px;" /></td>
                        <td style="text-align:left;padding-left:6px;width:75%;transform:translateY(-2px)">
                            <a style="color:#ffffff" v-bind:href="repo.owner.html_url" target="_blank"><h3>{{repo.owner.login}}</h3></a>
                            <a style="color:#02f2f2" v-bind:href="repo.html_url" target="_blank"><span style="font-size:14px"><br />/{{repo.name}}</span></a>
                        </td>
                        <td style="text-align:right;width:25%;transform:translateY(-2px);line-height:0.8;user-select:none;">
                            <span style="font-size:12px" v-bind:title="'Updated on ' + new Date(repo.updated_at)">{{formatTime(new Date() - new Date(repo.updated_at))}} <img src="data/finder_updated.png"/></span><br />
                            <span style="font-size:12px" v-bind:title="'Created on ' + new Date(repo.created_at)">{{formatTime(new Date() - new Date(repo.created_at))}} <img src="data/finder_created.png"/></span><br />
                            <span style="font-size:12px" v-bind:title="repo.stargazers_count.toLocaleString('en-US') + ' star' + (repo.stargazers_count == 1 ? '' : 's')">{{repo.stargazers_count.toLocaleString("en-US")}} <img src="data/finder_stars.png"/></span><br />
                            <span style="font-size:12px" v-bind:title="repo.open_issues_count.toLocaleString('en-US') + ' open issue' + (repo.open_issues_count == 1 ? '' : 's')">{{repo.open_issues_count.toLocaleString("en-US")}} <img src="data/finder_issues.png"/></span><br />
                        </td>
                    </tr>
                </table>
                <div style="display:table;font-size:12.5px;height:80px;width:calc(100% + 10px);background-color:#0000007f;margin:5px -5px;box-shadow:inset 0 0 100px #000000b0">
                    <div style="display:table-cell;vertical-align:middle">
                        <span v-if="!descFilter.includes(repo.description)"><i>"{{repo.description}}"</i><br /></span>
                        <span v-else><i style="opacity:0.5">No descriptions</i><br /></span>
                    </div>
                </div>
                <h5 style="margin:-5px">
                    <a class="navButton" v-bind:href="repo.homepage" v-bind:class="[repo.homepage == '' ? 'disabled' : '']" target="_blank">Homepage</a><!--
                 --><a class="navButton" v-bind:href="'https://' + repo.owner.login + '.github.io/' + repo.name" v-bind:class="[!repo.has_pages ? 'disabled' : '']" target="_blank">GitHub Pages</a><!--
                 --><a class="navButton" v-bind:href="'https://raw.githack.com/' + repo.owner.login + '/' + repo.name + '/' + repo.default_branch + '/'" target="_blank">raw.githack.com</a>
                </h5>
            </div>
        </div>
    </div>
</body>
